;*******************************************************
; MBR.asm
; selects boot partition and loads boot code from it
;*******************************************************

[ORG 0x1000]
[BITS 16]

; to properly setup code segment
jmp	0x0000:(START - 0x1000 + 0x7c00)

START:
	; start here
	; align segment registers and setup stack at 0x1000
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	sp, 0x1000

	; set video mode
	mov	ax, 3
	int	0x10

	; relocate entire MBR to 0x1000
	mov	si, 0x7c00
	mov	di, 0x1000
	mov	cx, 512

.relocate_loop:
	mov	al, [si]
	mov	[di], al
	inc	si
	inc	di
	loop	.relocate_loop

	; relocation finished
	jmp	0x0000:RELOCATED_START

;********************************************************
times	64 - ($ - $$) db 0

RELOCATED_START:
	; find bootable partition
	mov	si, 0x1000 + 446
	mov	cx, 4

.loop:
	; check for bootable sig
	mov	al, [si]
	and	al, 0x80
	jnz	.bootable
	loop	.loop

	; no bootable partition
	mov	si, msgNoBootable
	call	PrintString
	cli
	hlt

.bootable:
	; ds:si points to boot partition
	; get starting partition sector and save pointer and drive number
	mov	eax, [si + 8]
	mov	[DAPStart], eax
	push	si
	push	dx

LOADSECTORS:
	; load the boot sector at LBA in eax to 0x7c00
	mov	ah, 0		; reset the drive
	int	0x13		; call reset
	jc	.error		; error out if necessary
	mov	ah, 0x42
	mov	si, DAPSize
	int	0x13
	jnc	GOTOBOOTSEC

.error:
	mov	si, msgReadError
	call	PrintString
	cli
	hlt

GOTOBOOTSEC:
	; restore pointer and drive number
	pop	dx
	pop	si

	; goto bootsector
	jmp	0x0000:0x7c00

;*******************************
; data

msgNoBootable	db 13,10,"ERROR: No bootable partition found.",0
msgReadError	db 13,10,"ERROR: Could not read from disk.",0

DAPSize		dw 16
DAPCount	dw 1
DAPOffset	dw 0x7c00
DAPSegment	dw 0x0000
DAPStart	dq 0

;*******************************
; print a string
; si = pointer to string to print

PrintString:
	; setup registers for video out mode
	mov	ah, 0x0e
	mov	bh, 0x00
	mov	bl, 0x07

.loop:
	; get char
	lodsb		; same as "mov	al, [si] + inc	si"

	; check for nullchar
	or	al, al
	jz	.finish

	; if not null, print it & repeat
	int	0x10
	jmp	.loop

.finish:
	ret

;********************************************************
; ID string goes here (used to determine if it is the boot drive)
times	400 - ($ - $$) db 0
db "RAILGUN OS VERSION 0.4a  MBR BOOTSIG CXG98RKW",0

;********************************************************
; partition table goes here
times	446 - ($ - $$) db 0

;********************************************************
; bootsector signature
times	510 - ($ - $$) db 0
dw 0xaa55
